package search;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/*
 * PONDERING ALGORITHM
 * 1) engne searches on its time to say 20 ply and submits a move for play. 
  2) engine notes the 2nd move in the PV as the expected opponent move. 
  3) engine makes the expected ponder move on its internal board and starts a search for unlimited time until opponent moves. 
  4) The opponent makes a move: 
      4a) Ponder miss: engine effectively performs a takeback and then makes the opponents move and restarts the search as normal. 
      4b) Ponder Hit: 
            4b1) Not enough search (opponent quick move): Continue searching until satisfied. 
            4b2) Enough time: Make move. 
                 
 */
public class TimeControl {
	
	
	 /**
     * A regular expression for specifying time formats
     * Groups:
     * 1 => Moves per session
     * 2 => Base time minutes
     * 3 => Base time seconds, if any
     * 4 => Increment time in seconds
     */
    protected static Pattern timeControlsPattern =
            Pattern.compile("(\\d+) (\\d+)(?:\\:(\\d{2}))? (\\d+)");
    
    
    /*
     * The command to set a conventional time control looks like this:

  level 40 15 0            play 40 moves in 15 minutes, then next 40 in 15, etc.
  level 40 0:30 0
  
  The command to set an incremental time control looks like this:

  level 0 2 12
  
	Here the 0 means "play the whole game in this time control period", the 2 means "base=2 minutes", and the 12 means "inc=12 seconds". 
	As in conventional clock mode, the second argument to level can be in minutes and seconds.

The number of moves given in the level command (when non-zero) should be taken as the number of moves
 still to do before the specified time will be added to the clock, if the "level" command is received after some moves have already been played.
 
  The time given should be interpreted as the time left on its clock (including any time left over from the previous sessions), 
  and not necessarily the time that will be added to the clock after the specified number of moves has been played. 
  
  This is only relevant in WinBoard 4.3.xx, which might send the engine "level" commands during a game,
   just before the engine has to start thinking about the first move of a new time-control session. 
   
   Example: if at the start of the game "level 40 60 0" was given (40 moves per hour), and the engine receives "level 20 22 0" just before move 41,
    it should understand that it should do the next 20 moves in 22 minutes (pehaps because the secondary session was 20 moves per 15 minutes,
     and it had 7 minutes left on its clock after the first 40 moves).
     
The command to set an exact number of seconds per move looks like this:

  st 30
  
This means that each move must be made in at most 30 seconds. 
Time not used on one move does not accumulate for use on later moves.
     */
    
    /*  From H.G. Muller on winboard Forum in response to my question:
     * 
     * Say you want to bias time usage towards the beginning 
     * by allowing moves 20% more than their fair share, you could use

	targetTime = 1.3*timeLeft/(movesLeft+2.9);

	Then at the start of a session, with (say) 40 moves left, 
	you would assign 1/33 of the time to the move rather than 1/40. 
	While with 1 move left the target time would be 1/3 of the time left, so you could afford a factor 3 overrun.
     */
	public static  long getTimeForThisMove(long timeLeft, int movesLeft, long increment) {   // from jonatan petterssen
		
		long timeForThisMove = (long) ((1.1*timeLeft)/ movesLeft + (increment/2));
		//targetTime = 1.3*timeLeft/(movesLeft+2.9);
		
		// If the increment puts us above the total time left
		// use the timeleft - 0.5 seconds
		if(timeForThisMove >= timeLeft)
		  timeForThisMove = timeLeft -500;

		// If 0.5 seconds puts us below 0
		// use 0.1 seconds to atleast get some move.
		if(timeForThisMove < 0)
		  timeForThisMove = 100;

		return (long)  timeForThisMove;
	
	}
	public static final int GUESSEDLENGTH =40;

	// time-control variables
	//public static int startTime;
	
	public static  void setTimeLevel(String input) {
		Matcher matcher = timeControlsPattern.matcher(input.substring(6));
		  if(matcher.matches())
		  {
		      try
		      {
		          // Get moves per session (0 if not tournament mode)
		          int movesPerSession = Integer.parseInt(matcher.group(1));
		          // Get base time in milliseconds
		          long baseTime = Long.parseLong(matcher.group(2)) * 60 * 1000;
		        
		          
		          // Add seconds component, if any
		          if(matcher.group(3) != null)
		          {
		              baseTime += Long.parseLong(matcher.group(3)) * 1000;
		          }
		          Search2.baseTime=baseTime;
		          // Get move increment from seconds
		          long increment = Long.parseLong(matcher.group(4)) * 1000;
		          Search2.increment=increment;
		          // Set clock format on game
		          
		          
		          //System.out.println("moves per session " + movesPerSession + " baseTime " + baseTime + " increment " + increment);
		          
		          if(movesPerSession > 0) // Tournament format
		          {
		        	  Search2.movesPerSession=movesPerSession;
		          }
		      }
		      catch(NumberFormatException e)
		      {
		      }
		  }
	}
	
	public static void main ( String[]args) {
		
		long timeLeft = 900000;   //milisecs
		long movesLeft=40;
		
		double moveFudge=0.0;
				//2.9;
		double timeFudge=1.1;
		
		for (int i=0; i < 40; i ++) {
			
			long targetTime = (long) (timeFudge*timeLeft/(movesLeft+moveFudge));
			System.out.println("target Time " + targetTime + " timeLeft " + timeLeft + " movesLeft " + movesLeft);
			movesLeft--;
			timeLeft= timeLeft - targetTime;
		
		}
	} 
}
